import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.math.BigInteger;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;


public class LogAnalyzer {
	
	/*
	 * field
	 */
	private LinkedList<String> logFileNameList;//list of log file in the directory[file1.txt,file2.txt,,,]
	private LinkedList<Event> eventList;//event list sorted by time[e1,e2,e3,,,,]
	private boolean isUniqueEvent = true;//if unique event, event list is [e1,e2,e1,e4,,,]. not [e1,e1,e2,e2,e2,,,]

	private LinkedList<String> ignoreEventList;//ignore because background process
	
	
	/*
	 * constructor
	 */
	//reads all log file in logFileDirName directory
	public LogAnalyzer(String logFileDirName){
		//init fields
		logFileNameList = new LinkedList<String>();
		eventList = new LinkedList<Event>();

		try {
			File dir = new File(logFileDirName);
			String[] fileList = dir.list();
			for(int i=0;i<fileList.length;i++){
				String oneFileName = fileList[i];
//				System.out.println("filename:"+oneFileName);
				StringTokenizer st = new StringTokenizer(oneFileName,".");
				st.nextToken();
				String suffix = st.nextToken();
				if(suffix.equals("txt")){
					logFileNameList.add(logFileDirName+"/"+fileList[i]);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println("logFileNameList"+logFileNameList);
		
		//read ignore list
		readIgnoreList();

		//read log
		idsLogRead();
		
		//sort by time
		sortEventListByTime();
	}
	
	/*
	 * methods
	 */
	private void idsLogRead(){
		Iterator<String> logFileNameListIterator = logFileNameList.iterator();
		while(logFileNameListIterator.hasNext()){
			String oneLogFileName = logFileNameListIterator.next();
			idsLogReadForOneInputFile(oneLogFileName);
		}
	}
	
	private void idsLogReadForOneInputFile(String oneLogFileName){
		try {
			BufferedReader br = new BufferedReader(new FileReader(oneLogFileName));
			String oneLine;
			while((oneLine=br.readLine())!=null){
				idsLogReadForOneLine(oneLine);
			}
			br.close();
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("ERROR1");
		}
	}
	
	private void idsLogReadForOneLine(String oneLine){
		StringTokenizer st = new StringTokenizer(oneLine,"\t");
		//log validity check
		if(st.countTokens()!=9){
			st = null;
			return;
		}
		Event event = new Event();
		try {
			String processName = st.nextToken();
			//check the ignore list
			if(this.ignoreEventList.contains(processName)){
				st = null;
				event = null;
				return;
			}
			String typeOfAuditAction = st.nextToken();
			String path = st.nextToken();
			String resutlOfAction = st.nextToken();
			String returnValueOfAction = st.nextToken();
			String win_timestamp = st.nextToken();//ignore
			String hashOfUsername = st.nextToken();
			String plainDateTime = st.nextToken();
			String processID = st.nextToken();
			event.setProcessName(processName);
			event.setTypeOfAuditAction(typeOfAuditAction);
			event.setPath(path);
			event.setResultOfAction(resutlOfAction);
			event.setReturnValueOfAction(returnValueOfAction);
			event.setHashOfUsername(hashOfUsername);
			DateTransformer dt = new DateTransformer();
			Calendar cal = dt.getCalendarFromString(plainDateTime);
			event.setTimeStamp(cal);
			event.setProcessID(Long.parseLong(processID));
			
			//if unique event, then add to the eventList only unique one
			if(isUniqueEvent){
				//check whether first event
				if(this.eventList.size()!=0){
					//check the event is equal to the last event
					if(!(this.eventList.getLast().getProcessName()).equals(event.getProcessName())){
						this.eventList.add(event);
					}
				}
				//first event
				else{
					this.eventList.add(event);
				}
			}
			//if not unique event, then add the eventlist everything
			else{
				this.eventList.add(event);
			}
			


		} catch (Exception e) {
			//e.printStackTrace();
			event = null;
			st = null;
			System.out.println("ERROR2:"+oneLine);
		}
	}
	
	//read ignore_list.txt and set it to the ignoreEventList
	private void readIgnoreList(){
		ignoreEventList = new LinkedList<String>();
		try {
			BufferedReader br = new BufferedReader(new FileReader("ignore_list.txt"));
			String oneLine;
			while((oneLine=br.readLine())!=null){
				this.ignoreEventList.add(oneLine);
			}
			br.close();
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}
	
	
	
	//sort eventList and set First&End time
	private void sortEventListByTime(){
		Collections.sort(eventList,new EventComparatorByTime());
	}
	
	public void displayEventList(){
		Iterator<Event> eventListIterator = eventList.iterator();
		int i=0;
		while(eventListIterator.hasNext()){
			Event event = eventListIterator.next();
			System.out.println("EVENT["+i+"]"+event);
			i++;
		}
	}
	
	public void writeEventList(String outputFileName){
		try {
			BufferedWriter bw = new BufferedWriter(new FileWriter(outputFileName));
			//write first line
			bw.write("ProcessName"+"\t"+"typeOfAuditAction"+"\t"+"Path"+"\t"+"resultOfAction"+"\t"+"returnValueOfActioin"+"\t"+"timestamp"+"\t"+"hashOfUsername"+"\t"+"processID");
			bw.newLine();
			Iterator<Event> eventListIterator = eventList.iterator();
			while(eventListIterator.hasNext()){
				Event event = eventListIterator.next();
				bw.write(event.toString());
				bw.newLine();
			}
			bw.flush();
			bw.close();
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}
	
	

	public LinkedList<Event> getEventList() {
		return eventList;
	}

	

	
	

	

	

	

	
	





	/**
	 * @param args
	 */
	public static void main(String[] args) {
//		LogAnalyzer log = new LogAnalyzer("traininglog");
//		LinkedList<Event> eventList = log.getEventList();
//		IDSModelBuilderLogic model = new IDSModelBuilderLogic(eventList);
//		model.writeListForEventFreqScoreInTimeBin("out/eventfreq_score.csv");
//		model.writeMapForNGramScore("out/ngram_score.csv");
		
		LogAnalyzer logME = new LogAnalyzer("testlog_me");
		LinkedList<Event> eventListME = logME.getEventList();
		IDSModelBuilderLogic modelME = new IDSModelBuilderLogic(eventListME);
		modelME.writeMapForNGramScore("out/ngram_score_ME.csv");
		
		LogAnalyzer logOTHER = new LogAnalyzer("testlog_other");
		LinkedList<Event> eventListOTHER = logOTHER.getEventList();
		IDSModelBuilderLogic modelOTHER = new IDSModelBuilderLogic(eventListOTHER);
		modelOTHER.writeMapForNGramScore("out/ngram_score_OTHER.csv");
	}

}
